﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using Oxage.Common;
using Oxage.Midi;

namespace Oxage.Forms
{
	public partial class DirectMidiForm : UserControl, IConfigPanel
	{
		#region Members
		private DirectMidiConnector connector;
		private OpenFileDialog dialog = null;
		private string lastDLSPath = null;
		#endregion

		#region Constructors
		public DirectMidiForm()
		{
			InitializeComponent();

			cmbDevices.Text = "(connect to list devices)";

			cmbDevices.Enabled = false;
			lstInstruments.Enabled = false;
		}

		public DirectMidiForm(DirectMidiConnector connector) : this()
		{
			this.connector = connector;
			RefreshControls();
		}
		#endregion

		#region Properties
		public bool IsLocked
		{
			set
			{
				cmbDevices.Enabled = value;
				lstInstruments.Enabled = value;
			}
		}

		public string LastDLSPath
		{
			get
			{
				return this.lastDLSPath;
			}
		}

		public int Device
		{
			get
			{
				return cmbDevices.SelectedIndex;
			}
			set
			{
				if (cmbDevices.Items.Count > value)
				{
					cmbDevices.SelectedIndex = value;
				}
			}
		}

		public int Instrument
		{
			get
			{
				return lstInstruments.SelectedIndex;
			}
			set
			{
				if (lstInstruments.Items.Count > value)
				{
					lstInstruments.SelectedIndex = value;
				}
			}
		}
		#endregion

		#region Methods
		public void RefreshControls()
		{
			bool opened = this.connector.IsOpened;
			btnDefault.Enabled = opened;
			btnLoadDLS.Enabled = opened;
		}

		public void LoadDevices()
		{
			cmbDevices.Items.Clear();

			IEnumerable<DeviceInfo> devices = this.connector.GetDevices();
			foreach (DeviceInfo device in devices)
			{
				cmbDevices.Items.Add(device);
			}

			if (cmbDevices.Items.Count > 0)
			{
				cmbDevices.SelectedIndex = 0;
			}
		}

		public void LoadInstruments()
		{
			lstInstruments.Items.Clear();

			IEnumerable<MidiProgram> instruments = this.connector.GetProgramList();
			foreach (MidiProgram instrument in instruments)
			{
				lstInstruments.Items.Add(instrument);
			}

			if (lstInstruments.Items.Count > 0)
			{
				lstInstruments.SelectedIndex = 0;
			}
		}
		#endregion

		#region Event handlers
		private void btnDefault_Click(object sender, EventArgs e)
		{
			this.connector.LoadDLS(null);
			this.lastDLSPath = null;
		}

		private void btnLoadDLS_Click(object sender, EventArgs e)
		{
			string dir = null;
			if (dialog == null)
			{
				dialog = new OpenFileDialog();
				dialog.Filter = "DLS (*.dls)|*.dls";

				Config.Get("DirectoryForDLS", out dir);
				dialog.InitialDirectory = dir ?? Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
			}

			DialogResult result = dialog.ShowDialog();
			if (result == DialogResult.OK)
			{
				dir = Path.GetDirectoryName(dialog.FileName);
				Config.Set("DirectoryForDLS", dir);
				try
				{
					this.connector.LoadDLS(dialog.FileName);
					this.lastDLSPath = dialog.FileName;
				}
				catch (Exception ex)
				{
					Logger.Log(ex, LogLevels.Detailed);
				}
			}
		}

		private void cmbDevices_SelectedIndexChanged(object sender, EventArgs e)
		{
			DeviceInfo device = cmbDevices.SelectedItem as DeviceInfo;
			if (device != null && this.connector != null && this.connector.IsOpened)
			{
				this.connector.Close();
				this.connector.Open(device.PortInfo);
			}
		}

		private void lstInstruments_SelectedIndexChanged(object sender, EventArgs e)
		{
			MidiProgram program = lstInstruments.SelectedItem as MidiProgram;
			if (program != null)
			{
				this.connector.ProgramChange(program.Instrument);
			}
		}
		#endregion

		#region IConfigPanel Members
		public void SetProfile(Profile profile)
		{
			if (profile != null)
			{
				try
				{
					string path = profile["DirectMidiLastDLSPath"];
					this.connector.LoadDLS(path);
					this.lastDLSPath = path;
				}
				catch (Exception ex)
				{
					Logger.Log(ex, LogLevels.Detailed);
				}

				int device = 0;
				if (int.TryParse(profile["DirectMidiDeviceIndex"], out device))
				{
					this.Device = device;
				}

				int instrument = 0;
				if (int.TryParse(profile["DirectMidiInstrumentIndex"], out instrument))
				{
					this.Instrument = instrument;
				}
			}
		}

		public Profile GetProfile()
		{
			Profile profile = new Profile();
			profile["DirectMidiLastDLSPath"] = this.LastDLSPath;
			profile["DirectMidiDeviceIndex"] = this.Device.ToString();
			profile["DirectMidiInstrumentIndex"] = this.Instrument.ToString();
			return profile;
		}

		public UserControl GetUserControl()
		{
			return this;
		}
		#endregion
	}
}
